/*NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN

	Copyright (c) 2009 Jounayd Id Salah.
	All rights reserved.

	This file is part of Blacklib.

	Blacklib is free software: you can redistribute it and/or modify it under the 
	terms of the GNU Lesser General Public License as published by the Free Software 
	Foundation, either version 3 of the License, or (at your option) any later version.
	Blacklib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 
	without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
	PURPOSE.  See the GNU Lesser General Public License for more details.
	You should have received a copy of the GNU Lesser General Public License along with 
	Blacklib.  If not, see <http://www.gnu.org/licenses/>.
*/
//NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN

namespace black
{
	static unsigned int			g_uiSeed;
	bALIGN16 static __m128i		g_mmiSeed;

	void initRand( const unsigned int seed )
	{
		g_uiSeed	= seed;
#ifdef bSSE
		g_mmiSeed	= _mm_set_epi32( seed, seed+1, seed, seed+1 );
#endif
	}

	/** from by Kipp Owens and Rajiv Parikh at Intel.
	According to Intel, it's 2 times faster than standard rand(). */
	int rand()
	{
		g_uiSeed = ( 214013 * g_uiSeed + 2531011 );
		return ( g_uiSeed >> 16 ) & 0x7FFF;
	}

	/** from by Kipp Owens and Rajiv Parikh at Intel.
	According to Intel, it's 5 times faster than standard rand().
	Copyright (c) 2003 Intel Corporation */
	void rand( __m128i& mmiRes )
	{
#ifdef bSSE
		__m128i cur_seed_split;
		__m128i multiplier;

		bALIGN16 static const unsigned int mult[4]		= { 214013, 17405, 214013, 69069 };
		bALIGN16 static const unsigned int gadd[4]		= { 2531011, 10395331, 13737667, 1 };
		bALIGN16 static const unsigned int mask[4]		= { 0xFFFFFFFF, 0, 0xFFFFFFFF, 0 };

		static __m128i adder		= _mm_load_si128( (__m128i*) gadd );
		static __m128i mod_mask		= _mm_load_si128( (__m128i*) mask );

		multiplier		= _mm_load_si128( (__m128i*) mult );
		cur_seed_split	= _mm_shuffle_epi32( g_mmiSeed, _MM_SHUFFLE( 2, 3, 0, 1 ) );
		g_mmiSeed		= _mm_mul_epu32( g_mmiSeed, multiplier );
		multiplier		= _mm_shuffle_epi32( multiplier, _MM_SHUFFLE( 2, 3, 0, 1 ) );
		cur_seed_split	= _mm_mul_epu32( cur_seed_split, multiplier );
		g_mmiSeed		= _mm_and_si128( g_mmiSeed, mod_mask);
		cur_seed_split	= _mm_and_si128( cur_seed_split, mod_mask );
		cur_seed_split	= _mm_shuffle_epi32( cur_seed_split, _MM_SHUFFLE( 2, 3, 0, 1 ) );
		g_mmiSeed		= _mm_or_si128( g_mmiSeed, cur_seed_split );
		g_mmiSeed		= _mm_add_epi32( g_mmiSeed, adder);

		mmiRes = g_mmiSeed;
#endif
	}
}
